<?php
namespace app\api\controller;

use think\Controller;
use think\facade\Log;
use app\service\MqttPublisher;
use app\service\Protocol\ProtocolFactory;

/**
 * 设备指令下发控制器（简化版）
 */
class DeviceCommand extends Controller
{
    public function send()
    {
        try {
            // 获取请求数据
            $requestData = $this->request->post();

            // 验证必填字段
            if (empty($requestData['mac'])) {
                return json([
                    'code' => 0,
                    'message' => 'MAC地址不能为空'
                ]);
            }

            if (empty($requestData['type'])) {
                return json([
                    'code' => 0,
                    'message' => '指令类型不能为空'
                ]);
            }

            $mac = $requestData['mac'];
            $type = $requestData['type'];
            $params = isset($requestData['params']) ? $requestData['params'] : [];

            // 获取协议类型，默认为vendor1（现有协议）
            $vendor = $requestData['vendor'] ?? 'vendor1';

            // 验证MAC地址格式
            if (!$this->isValidMac($mac)) {
                return json([
                    'code' => 0,
                    'message' => 'MAC地址格式无效'
                ]);
            }

            // 验证参数格式
            if (!empty($params) && !is_array($params)) {
                return json([
                    'code' => 0,
                    'message' => '参数格式无效，必须是数组'
                ]);
            }

            // 使用协议工厂创建协议适配器
            try {
                $protocol = ProtocolFactory::create($vendor);
                Log::info("已选择协议: {$vendor} ({$protocol->getName()})");
            } catch (\Exception $e) {
                Log::error("协议选择失败: " . $e->getMessage());
                return json([
                    'code' => 0,
                    'message' => '不支持的协议: ' . $vendor
                ]);
            }

            // 使用协议适配器构建指令
            $commandResult = $protocol->buildCommand($mac, $type, $params);
            $topic = $commandResult['topic'];
            $message = $commandResult['message'];

            Log::info("指令已构建: 主题={$topic}, 消息长度=" . strlen($message));

            // 直接发送MQTT消息
            $result = $this->sendMqttMessage($topic, $message);

            if ($result) {
                Log::info("设备指令发送成功: MAC={$mac}, 类型={$type}, 协议={$vendor}");

                return json([
                    'code' => 1,
                    'message' => '指令发送成功',
                    'data' => [
                        'mac' => $mac,
                        'type' => $type,
                        'vendor' => $vendor,
                        'params' => $params,
                        'topic' => $topic,
                        'message' => $message,
                        'timestamp' => date('Y-m-d H:i:s')
                    ]
                ]);
            } else {
                Log::error("设备指令发送失败: MAC={$mac}, 类型={$type}");

                return json([
                    'code' => 0,
                    'message' => '指令发送失败'
                ]);
            }

        } catch (\Throwable $e) {
            Log::error("设备指令下发异常: " . $e->getMessage() . "\n" . $e->getTraceAsString());

            return json([
                'code' => 0,
                'message' => '系统异常: ' . $e->getMessage()
            ]);
        }
    }

    /**
     * 直接发送MQTT消息
     * @param string $topic MQTT主题
     * @param string $message 消息内容
     * @return bool 发送结果
     */
    private function sendMqttMessage(string $topic, string $message): bool
    {
        try {
            // 获取MQTT配置
            $mqttConfig = config('mqtt');
            if (empty($mqttConfig)) {
                // 如果配置为空，直接加载配置文件
                $configFile = app()->getConfigPath() . 'mqtt.php';
                if (file_exists($configFile)) {
                    $mqttConfig = include $configFile;
                } else {
                    Log::error("MQTT配置文件不存在: " . $configFile);
                    return false;
                }
            }

            Log::info("MQTT发送开始: topic={$topic}, message=" . substr($message, 0, 200));

            // 尝试使用simps/mqtt库
            try {
                // 创建MQTT客户端配置 - 使用ClientConfig对象
                $clientConfig = new \Simps\MQTT\Config\ClientConfig();
                $clientConfig->setHost($mqttConfig['host'])
                            ->setPort($mqttConfig['port'])
                            ->setUsername($mqttConfig['username'])
                            ->setPassword($mqttConfig['password'])
                            ->setClientId('api_' . uniqid() . '_' . getmypid())
                            ->setKeepAlive($mqttConfig['keepalive'] ?? 60)
                            ->setCleanSession($mqttConfig['clean_session'] ?? true)
                            ->setConnectTimeout($mqttConfig['timeout'] ?? 5);

                // 创建MQTT客户端
                $client = new \Simps\MQTT\Client($clientConfig);

                Log::info("MQTT连接中: {$mqttConfig['host']}:{$mqttConfig['port']}");

                // 连接到MQTT服务器
                $connectResult = $client->connect();

                if ($connectResult !== true && !is_array($connectResult)) {
                    Log::error("MQTT连接失败");
                    return false;
                }

                Log::info("MQTT连接成功");

                // 发布消息
                $publishResult = $client->publish($topic, $message, 0);

                if ($publishResult) {
                    Log::info("MQTT消息发布成功: topic={$topic}");
                    $result = true;
                } else {
                    Log::error("MQTT消息发布失败: topic={$topic}");
                    $result = false;
                }

                // 关闭连接
                $client->close();
                Log::info("MQTT连接已关闭");

                return $result;

            } catch (\Throwable $e) {
                Log::warning("simps/mqtt库调用失败，尝试使用原生socket: " . $e->getMessage());

                // 备用方案：使用原生socket发送MQTT消息
                return $this->sendMqttMessageWithSocket($mqttConfig, $topic, $message);
            }

        } catch (\Throwable $e) {
            Log::error("MQTT发送异常: " . $e->getMessage() . " 文件: " . $e->getFile() . " 行号: " . $e->getLine());
            return false;
        }
    }

    /**
     * 使用原生socket发送MQTT消息（备用方案）
     */
    private function sendMqttMessageWithSocket(array $config, string $topic, string $message): bool
    {
        try {
            Log::info("使用原生socket发送MQTT消息");

            // 创建socket连接
            $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
            if (!$socket) {
                Log::error("创建socket失败");
                return false;
            }

            // 连接到MQTT服务器
            $result = socket_connect($socket, $config['host'], $config['port']);
            if (!$result) {
                Log::error("连接MQTT服务器失败");
                socket_close($socket);
                return false;
            }

            Log::info("Socket连接MQTT服务器成功");

            // 发送CONNECT包
            $connectPacket = $this->buildMqttConnectPacket($config);
            socket_write($socket, $connectPacket);

            // 读取CONNACK
            $response = socket_read($socket, 4);
            if (strlen($response) < 4 || ord($response[3]) !== 0) {
                Log::error("MQTT连接认证失败");
                socket_close($socket);
                return false;
            }

            Log::info("MQTT认证成功");

            // 发送PUBLISH包
            $publishPacket = $this->buildMqttPublishPacket($topic, $message);
            $writeResult = socket_write($socket, $publishPacket);

            if ($writeResult === false) {
                Log::error("发送消息失败");
                socket_close($socket);
                return false;
            }

            Log::info("消息发送成功，字节数: " . $writeResult);

            // 关闭连接
            socket_close($socket);

            return true;

        } catch (\Throwable $e) {
            Log::error("Socket MQTT发送异常: " . $e->getMessage());
            return false;
        }
    }

    /**
     * 构建MQTT CONNECT包
     */
    private function buildMqttConnectPacket(array $config): string
    {
        $clientId = 'api_' . uniqid();
        $username = $config['username'];
        $password = $config['password'];

        // MQTT协议名
        $protocolName = 'MQTT';
        $protocolLevel = 4; // MQTT 3.1.1

        // 连接标志
        $connectFlags = 0;
        $connectFlags |= 0x02; // Clean Session
        if ($username) $connectFlags |= 0x80; // Username Flag
        if ($password) $connectFlags |= 0x40; // Password Flag

        // Keep Alive
        $keepAlive = 60;

        // 构建可变头部
        $variableHeader = '';
        $variableHeader .= pack('n', strlen($protocolName)) . $protocolName;
        $variableHeader .= chr($protocolLevel);
        $variableHeader .= chr($connectFlags);
        $variableHeader .= pack('n', $keepAlive);

        // 构建载荷
        $payload = '';
        $payload .= pack('n', strlen($clientId)) . $clientId;
        if ($username) {
            $payload .= pack('n', strlen($username)) . $username;
        }
        if ($password) {
            $payload .= pack('n', strlen($password)) . $password;
        }

        // 计算剩余长度
        $remainingLength = strlen($variableHeader) + strlen($payload);

        // 构建固定头部
        $fixedHeader = chr(0x10); // CONNECT消息类型
        $fixedHeader .= $this->encodeMqttRemainingLength($remainingLength);

        return $fixedHeader . $variableHeader . $payload;
    }

    /**
     * 构建MQTT PUBLISH包
     */
    private function buildMqttPublishPacket(string $topic, string $message): string
    {
        // 构建可变头部
        $variableHeader = pack('n', strlen($topic)) . $topic;

        // 载荷就是消息内容
        $payload = $message;

        // 计算剩余长度
        $remainingLength = strlen($variableHeader) + strlen($payload);

        // 构建固定头部
        $fixedHeader = chr(0x30); // PUBLISH消息类型，QoS=0
        $fixedHeader .= $this->encodeMqttRemainingLength($remainingLength);

        return $fixedHeader . $variableHeader . $payload;
    }

    /**
     * 编码MQTT剩余长度
     */
    private function encodeMqttRemainingLength(int $length): string
    {
        $encoded = '';
        do {
            $digit = $length % 128;
            $length = intval($length / 128);
            if ($length > 0) {
                $digit |= 0x80;
            }
            $encoded .= chr($digit);
        } while ($length > 0);

        return $encoded;
    }

    /**
     * 根据IMEI获取设备MAC地址
     *
     * @param string $imei
     * @return string|null
     */
    private function getDeviceMacByImei(string $imei): ?string
    {
        try {
            // 从数据库查询设备MAC地址
            $device = \think\Db::name('flow_wifi_imei')
                ->field('mac')
                ->where('IMEI', $imei)
                ->find();

            if ($device && !empty($device['mac'])) {
                return $device['mac'];
            }

            Log::warning("未找到IMEI对应的MAC地址: IMEI={$imei}");
            return null;

        } catch (\Throwable $e) {
            Log::error("查询设备MAC地址失败: IMEI={$imei}, 错误=" . $e->getMessage());
            return null;
        }
    }

    /**
     * 验证MAC地址格式
     *
     * @param string $mac
     * @return bool
     */
    private function isValidMac(string $mac): bool
    {
        // MAC地址格式：12位十六进制字符，可以有冒号分隔
        // 支持格式：1C3426522542 或 1C:34:26:52:25:42
        $mac = strtoupper(str_replace(':', '', $mac));
        return preg_match('/^[0-9A-F]{12}$/', $mac);
    }

    /**
     * 验证IMEI格式（保留兼容性）
     *
     * @param string $imei
     * @return bool
     */
    private function isValidImei(string $imei): bool
    {
        // IMEI必须是15位数字
        return preg_match('/^\d{15}$/', $imei);
    }

    /**
     * 验证设备ID格式（保留兼容性）
     *
     * @param string $deviceId
     * @return bool
     */
    private function isValidDeviceId(string $deviceId): bool
    {
        // IMEI: 15位数字
        if (preg_match('/^\d{15}$/', $deviceId)) {
            return true;
        }

        // MAC地址: XX:XX:XX:XX:XX:XX 或 XXXXXXXXXXXX
        if (preg_match('/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/', $deviceId) ||
            preg_match('/^[0-9A-Fa-f]{12}$/', $deviceId)) {
            return true;
        }

        // 设备序列号: 字母数字组合，6-20位
        if (preg_match('/^[A-Za-z0-9]{6,20}$/', $deviceId)) {
            return true;
        }

        return false;
    }

    /**
     * 验证指令格式
     *
     * @param mixed $commands
     * @return bool
     */
    private function isValidCommands($commands): bool
    {
        // 必须是数组
        if (!is_array($commands)) {
            return false;
        }

        // 必须包含cmds字段
        if (!isset($commands['cmds']) || !is_array($commands['cmds'])) {
            return false;
        }

        // 验证每个指令
        foreach ($commands['cmds'] as $cmd) {
            if (!is_array($cmd) || empty($cmd['cmd_name'])) {
                return false;
            }
        }

        return true;
    }

    /**
     * 获取支持的指令类型列表
     * GET /api/device/commands
     */
    public function getSupportedCommands()
    {
        $commands = \app\service\DeviceCommandTemplates::getSupportedTypes();

        return json([
            'code' => 1,
            'message' => '查询成功',
            'data' => $commands
        ]);
    }

    /**
     * 获取API调用示例
     * GET /api/device/command/examples
     */
    public function getExamples()
    {
        $examples = [
            'api_format' => [
                'description' => 'API请求格式',
                'request' => [
                    'mac' => '1C3426522542',
                    'type' => 'reboot'
                ],
                'response' => [
                    'code' => 1,
                    'message' => '指令发送成功',
                    'data' => [
                        'mac' => '1C3426522542',
                        'type' => 'reboot',
                        'type_name' => '设备重启',
                        'description' => '立即重启设备',
                        'topic' => 'tc/device/in/1C3426522542',
                        'commands' => [
                            'cmds' => [
                                ['cmd_name' => 'reboot']
                            ]
                        ],
                        'timestamp' => '2025-09-12 12:30:45'
                    ]
                ]
            ],
            'examples' => [
                'reboot' => [
                    'mac' => '1C3426522542',
                    'type' => 'reboot'
                ],
                'hotspot_config' => [
                    'mac' => '1C3426522542',
                    'type' => 'hotspot_config'
                ],
                'hotspot_modify' => [
                    'mac' => '1C3426522542',
                    'type' => 'hotspot_modify',
                    'params' => [
                        'hotspot_name' => 'MyWiFi',
                        'hotspot_password' => '12345678',
                        'hotspot_connected_num_max' => 10,
                        'hotspot_get_hidden' => 0,
                        'hotspot_band' => 1
                    ]
                ],
                'sim_switch_slot1' => [
                    'mac' => '1C3426522542',
                    'type' => 'sim_switch_slot1'
                ],
                'speed_limit_10m' => [
                    'mac' => '1C3426522542',
                    'type' => 'speed_limit_10m'
                ],
                'report_status' => [
                    'mac' => '1C3426522542',
                    'type' => 'report_status'
                ]
            ]
        ];

        return json([
            'code' => 1,
            'message' => '查询成功',
            'data' => $examples
        ]);
    }
}
